#include	<cuda_runtime.h>
#include	<cublas_v2.h>
#include	<sys/time.h>
#include	<iostream>
using	namespace	std;
cublasHandle_t	handle;

template<size_t	R,	size_t	C>
struct	Matrix{
	float	*data;
	Matrix(){	cudaMallocManaged(&data,	R*C*sizeof(float));	}
	~Matrix(){	cudaFree(data);	}
};

template<size_t	N>
void	bench(){
	Matrix<N,N>	a,	b,	c;
	timeval	beg,	end;
	gettimeofday(&beg,NULL);
	for(size_t	it=0;	it<0x1000000ull/N;	it++){
		float	alf=1,	bet=0;
		cublasGemmEx(handle, CUBLAS_OP_T, CUBLAS_OP_N, N, N, N, &alf, a.data, CUDA_R_32F,N, b.data, CUDA_R_32F,N, &bet, c.data, CUDA_R_32F,N,CUBLAS_COMPUTE_32F_FAST_16BF,CUBLAS_GEMM_DEFAULT); 
	}
	gettimeofday(&end,NULL);
	double	t=(end.tv_sec-beg.tv_sec+1e-6*(end.tv_usec-beg.tv_usec));
	double	f=(double)N*N*N*2;
	cerr<<"N="<<N<<'\t'<<0x1000000ull/N*f/1024/1024/1024/1024/t<<" TFLOPS\n";
}

int	main(int	ac,	char	**av){
	cublasCreate(&handle);
	bench<16>();
	bench<32>();
	bench<64>();	
	bench<128>();
	bench<256>();
	bench<512>();	
	bench<1024>();
	bench<2048>();
	bench<4096>();
	cublasDestroy(handle);
	return	0;
}

